package config

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
	"wzgames/pkg/utils/stringutil"
)

type JSONConfig struct {
}

func (j *JSONConfig) Load(file string) (ConfData, error) {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		return nil, err
	}
	data, err := os.ReadFile(file)
	if err != nil {
		return nil, err
	}
	return j.Parse(data)
}

func (j *JSONConfig) Parse(data []byte) (ConfData, error) {
	o := &JSONConfData{
		data: make(map[string]interface{}),
	}
	err := json.Unmarshal(data, &o.data)
	if err != nil {
		var arrData []interface{}
		err2 := json.Unmarshal(data, &arrData)
		if err2 != nil {
			return nil, err
		}
		o.data["data"] = arrData
	}

	return o, nil
}

type JSONConfData struct {
	data map[string]interface{}
	sync.RWMutex
}

func (jo *JSONConfData) ReplaceData(d map[string]interface{}) {
	jo.Lock()
	defer jo.Unlock()

	jo.data = d
}

func (jo *JSONConfData) getData(key string) interface{} {
	jo.Lock()
	defer jo.Unlock()

	if v, ok := jo.data[key]; ok {
		return v
	}
	return nil
}

func (jo *JSONConfData) GetString(key string, defaultVal ...string) string {
	val := jo.getData(key)
	if val != nil {
		if v, ok := val.(string); ok {
			return v
		}
	}
	if len(defaultVal) > 0 {
		return defaultVal[0]
	}
	return ""
}

func (jo *JSONConfData) GetInt(key string, defaultVal ...int) int {
	val := jo.getData(key)
	if val != nil {
		if v, ok := val.(float64); ok {
			return int(v)
		}
	}
	if len(defaultVal) > 0 {
		return defaultVal[0]
	}
	return 0
}

func (jo *JSONConfData) GetInt64(key string, defaultVal ...int64) int64 {
	val := jo.getData(key)
	if val != nil {
		if v, ok := val.(float64); ok {
			return int64(v)
		}
	}
	if len(defaultVal) > 0 {
		return defaultVal[0]
	}
	return 0
}

func (jo *JSONConfData) GetBool(key string) (bool, error) {
	val := jo.getData(key)
	if val != nil {
		return stringutil.ToBoolean(val)
	}
	return false, fmt.Errorf("[Config] json not exist key: %q", key)
}

func (jo *JSONConfData) GetFloat64(key string, defaultVal ...float64) float64 {
	val := jo.getData(key)
	if val != nil {
		if v, ok := val.(float64); ok {
			return v
		} else if v, ok := val.(int); ok {
			return float64(v)
		} else if v, ok := val.(int64); ok {
			return float64(v)
		}
	}
	if len(defaultVal) > 0 {
		return defaultVal[0]
	}
	return 0.0
}

func (jo *JSONConfData) GetRawValue(key string) interface{} {
	return jo.getData(key)
}

func (jo *JSONConfData) SetRawValue(key string, val interface{}) {
	jo.Lock()
	defer jo.Unlock()

	jo.data[key] = val
}

func (jo *JSONConfData) ForEachKey(fn func(string, interface{})) {
	jo.Lock()
	defer jo.Unlock()
	for k, v := range jo.data {
		fn(k, v)
	}
}

func (jo *JSONConfData) SaveFile(file string) error {
	f, err := os.Create(file)
	if err != nil {
		return err
	}
	defer f.Close()
	b, err := json.MarshalIndent(jo.data, "", "  ")
	if err != nil {
		return err
	}
	_, err = f.Write(b)
	return err
}

func init() {
	Register("json", &JSONConfig{})
}
